﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Service.Core.Utils;
using Service.Framework.ApplicationEventBus;
using Service.Framework.OperationLog;
using Service.Framework.Utils;
using System.Collections;
using System.Diagnostics;
using System.Security.Claims;
using System.Text.RegularExpressions;

namespace Service.Core.Filters
{
    /// <summary>
    /// 操作日志过滤器
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class OperateLogFilterAttribute : ActionFilterAttribute
    {
        private static readonly HashSet<Type> SimpleTypes =
        [
            typeof(string),
            typeof(decimal),
            typeof(DateTime),
            typeof(DateTimeOffset),
            typeof(TimeSpan),
            typeof(Guid)
        ];

        private readonly string[] _desensitizationName;

        /// <summary>
        /// 日志消息
        /// </summary>
        private readonly string _msg;

        /// <summary>
        /// 日志名称
        /// </summary>
        private readonly string _name;


        private readonly OperationLogType _type;
        private readonly string _result;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="msg"></param>
        /// <param name="type"></param>
        /// <param name="result"></param>
        /// <param name="desensitizationName"></param>
        public OperateLogFilterAttribute(string name, string msg, OperationLogType type = OperationLogType.Operation,
            string result = "", params string[] desensitizationName)
        {
            _msg = msg;
            this._name = name;
            this._type = type;
            this._result = result;
            _desensitizationName = desensitizationName;
        }

        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var logger =
                context.HttpContext.RequestServices.GetService(typeof(ILogger<OperateLogFilterAttribute>)) as
                    ILogger<OperateLogFilterAttribute>;
            var sw = new Stopwatch();
            sw.Start();
            var actionResult = await next();
            sw.Stop();

            //数据脱敏
            if (_desensitizationName != null && _desensitizationName.Any())
            {
                MaskSensitiveDataRecursive(context.ActionArguments);
            }

            var args = JsonConvert.SerializeObject(context.ActionArguments);
            var result = string.Empty;
            //先判断异常是否为空
            if (actionResult is { Exception: not null })
                result = actionResult.Exception.Message;
            else if (!string.IsNullOrWhiteSpace(_result))
                result = _result;
            else if (actionResult.Result.GetType() == typeof(EmptyResult))
                result = "";
            else result = JsonConvert.SerializeObject(((ObjectResult)actionResult.Result)?.Value);

            //if (Encrypted)
            //{
            //    args = GZipDecompress.GetStringByData(args);
            //    result = GZipDecompress.GetStringByData(result);
            //}

            var _httpContextAccessor =
                context.HttpContext.RequestServices.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
            var request = _httpContextAccessor.HttpContext?.Request;
            var ua = request?.Headers["User-Agent"].ToString();

            var devicePlatform = request?.Headers["device-platform"].ToString();
            var deviceId = request?.Headers["device-id"].ToString();
            var version = request?.Headers["version"].ToString();
            var controller = ((ControllerActionDescriptor)context.ActionDescriptor).ControllerName.ToLower();
            var action = ((ControllerActionDescriptor)context.ActionDescriptor).ActionName.ToLower();

            var userId = _httpContextAccessor.HttpContext?.User?.FindFirst("sub")?.Value;
            var clientId = _httpContextAccessor.HttpContext?.User?.FindFirst("client_id")?.Value;

            var log = new OperationLogDto(_msg,
                context.HttpContext.Request.Method.ToLower(),
                $"/{controller}/{action}",
                sw.ElapsedMilliseconds,
                args,
                result,
                ua,
                context.HttpContext?.GetRequestIp(),
                _name,
                _type,
                userId,
                clientId,
                devicePlatform, deviceId, version);
            logger.LogInformation("操作日志：{Name}-{_msg}-{Dto}", _name, _msg, JsonConvert.SerializeObject(log));
            var operationLogService = context.HttpContext.RequestServices.GetService<IApplicationEventBus>();
            if (operationLogService != null)
            {
                _ = operationLogService.PublishAsync(new OperationLogAges(log));
            }
        }


        // 递归脱敏核心逻辑
        private void MaskSensitiveDataRecursive(object obj)
        {
            if (obj == null) return;
            var type = obj.GetType();
            // 处理字典类型（如 dynamic 或 Dictionary<string, object>）
            if (obj is IDictionary dictionary)
            {
                foreach (DictionaryEntry entry in dictionary)
                {
                    if (entry.Value != null && _desensitizationName.Contains(entry.Key.ToString()))
                    {
                        dictionary[entry.Key] = "***REDACTED***"; // 脱敏
                    }
                    else
                    {
                        MaskSensitiveDataRecursive(entry.Value); // 递归检查值
                    }
                }

                return;
            }

            // 处理集合类型（如 List<T>）
            if (obj is IEnumerable enumerable && !(obj is string))
            {
                foreach (var item in enumerable)
                {
                    if (item != null && !IsSimpleType(item.GetType()))
                    {
                        MaskSensitiveDataRecursive(item);
                    }
                 
                }

                return;
            }

            // 处理普通对象
            foreach (var prop in type.GetProperties())
            {
                // 如果是敏感字段，直接脱敏
                if (_desensitizationName.Contains(prop.Name))
                {
                    prop.SetValue(obj, "***REDACTED***");
                    continue;
                }

                // 递归处理嵌套对象
                var value = prop.GetValue(obj);
                if (value == null) continue;

                // 如果是简单类型（如 int, string, DateTime），跳过
                if (value.GetType().IsPrimitive || value is string) continue;

                MaskSensitiveDataRecursive(value);
            }
        }

        public static string GetIP(HttpRequest request)
        {
            if (request == null)
            {
                return "";
            }

            var ip = request.Headers["X-Real-IP"].FirstOrDefault();
            if (ip.IsNullOrEmpty())
            {
                ip = request.Headers["X-Forwarded-For"].FirstOrDefault();
            }

            if (ip.IsNullOrEmpty())
            {
                ip = request.HttpContext?.Connection?.RemoteIpAddress?.ToString();
            }

            if (ip.IsNullOrEmpty() || !IsIp(ip))
            {
                ip = "127.0.0.1";
            }

            return ip;
        }

        /// <summary>
        /// 是否为ip
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public static bool IsIp(string ip)
        {
            return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
        }



        // 扩展简单类型判断
        private static bool IsSimpleType(Type type)
        {
            return type.IsPrimitive
                   || SimpleTypes.Contains(type)
                   || type.IsEnum;
        }
    }
}